<template>
    <div class="list-warrper">
        <canvas id="myCanvas" width="800" height="300" style="border: 1px solid #d3d3d3; background: #ffffff; margin-top: 20px" />
        <div id="temp" class="temp"></div>
    </div>
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop, Watch } from 'vue-property-decorator';

// const CIRCLE_RADIUS = 40 // 大圆的半径
// const SMALL_CIRCLE_RADIUS = 20 // 小圆的半价
const START_IMAGE_WIDTH = 80;
const START_IMAGE_HEIGHT = 84;
const START_X = 50; // X轴起始位置
const START_Y = 120; // Y轴起始位置
const END_X = 700; // X轴结束位置
const END_Y = 120; // Y轴结束位置
const PROCESS_WIDTH = 100;
const CONDOTION_CIRCLE = 10; // 条件的半径
const TEXT_LEFT_MARGIN = 10; // 字体离左边框的间距
const TEXT_TOP_MARGIN = 5; // 字体离上边框的间距
const MEDIUM_LINE_LENGTH = 80; // 中等线的长度 一般用于流程间的链接
const SMALL_LINE_LENGTH = 20; // 短线的长度
// const FIRST_PROCESS_START_X = START_X + PROCESS_WIDTH + MEDIUM_LINE_LENGTH // 180
const FIRST_PROCESS_START_X = START_X + START_IMAGE_WIDTH; // 180
const FIRST_PROCESS_START_Y = START_Y - PROCESS_WIDTH / 2; // 165
interface ConditionArrayConfig {
    x: number;
    y: number;
    conditionExpression: string;
}
@Component({
    name: 'bpmn-canvas'
})
export default class list extends Vue {
    @Prop({ default: true }) jsonData: any[];
    startImg = require('@/assets/common/start.png');
    endImg = require('@/assets/common/end.png');
    nodeImg: any = '';
    arrow_color: string = '';
    conditionArray: ConditionArrayConfig[] = [];
    startX: number = 0;
    @Watch('jsonData')
    onJsonDataChange(val) {
        if (val.length) {
            this.draw();
        }
    }
    // 自动换行的文字
    drawTextAuto(ctx, t, x, y, w) {
        var chr = t.split('');
        var temp = '';
        var row: string[] = [];
        ctx.textBaseline = 'middle';
        for (var a = 0; a < chr.length; a++) {
            if (!(ctx.measureText(temp).width < w)) {
                row.push(temp);
                temp = '';
            }
            temp += chr[a];
        }

        row.push(temp);

        for (var b = 0; b < row.length; b++) {
            ctx.fillText(row[b], x, y + (b + 1) * 20);
        }
    }

    imageToCanvas(ctx, url, x, y, width?, height?, hasText?, text?) {
        var img = new Image();
        img.src = url;
        const that = this;
        img.onload = function () {
            if (width && height) {
                ctx.drawImage(img, x, y, width, height);
                if (hasText) {
                    that.drawTextAuto(ctx, text, x + PROCESS_WIDTH / 2, y + 20, PROCESS_WIDTH / 2);
                }
            } else {
                ctx.drawImage(img, x, y);
            }
        };
    }
    drawLineWithArrow(ctx, fromX, fromY, toX, toY, color) {
        var headlen = 6; //自定义箭头线的长度
        var theta = 45; //自定义箭头线与直线的夹角，个人觉得45°刚刚好
        var arrowX, arrowY; //箭头线终点坐标
        // 计算各角度和对应的箭头终点坐标
        var angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI;
        var angle1 = ((angle + theta) * Math.PI) / 180;
        var angle2 = ((angle - theta) * Math.PI) / 180;
        var topX = headlen * Math.cos(angle1);
        var topY = headlen * Math.sin(angle1);
        var botX = headlen * Math.cos(angle2);
        var botY = headlen * Math.sin(angle2);
        // ctx.beginPath()
        ctx.lineWidth = 2;
        //画直线
        ctx.moveTo(fromX, fromY);
        ctx.lineTo(toX, toY);

        arrowX = toX + topX;
        arrowY = toY + topY;
        //画上边箭头线
        ctx.moveTo(arrowX, arrowY);
        ctx.lineTo(toX, toY);

        arrowX = toX + botX;
        arrowY = toY + botY;
        //画下边箭头线
        ctx.lineTo(arrowX, arrowY);
        ctx.strokeStyle = color;
        // ctx.stroke()
    }

    //   设置高亮颜色
    customerStrokeStyle(item, ctx, arrow_color) {
        if (item.currentFlag) {
            ctx.strokeStyle = '#186CFF';
            this.arrow_color = '#186CFF';
            this.nodeImg = require('@/assets/common/node_active.png');
        } else {
            if (item.passFlag) {
                ctx.strokeStyle = 'rgb(150,188,255)';
                this.arrow_color = 'rgb(150,188,255)';
                this.nodeImg = require('@/assets/common/node_active.png');
            } else {
                ctx.strokeStyle = '#C6CEDB';
                this.arrow_color = '#C6CEDB';
                this.nodeImg = require('@/assets/common/node.png');
            }
        }
    }
    //   画矩形
    drawRect(ctx, x, y, width, height) {
        ctx.beginPath();
        ctx.strokeRect(x, y, width, height);
        ctx.stroke();
    }
    // 画文本
    drawText(ctx, text, x, y) {
        ctx.beginPath();
        ctx.fillText(text, x, y);
        ctx.stroke();
    }
    //   画条件值
    drawCondition(ctx, text, condition_start_x, condition_end_y, item) {
        ctx.beginPath();
        ctx.strokeStyle = '#333';
        ctx.textAlign = 'center';
        ctx.lineWidth = 1;
        ctx.moveTo(condition_start_x, condition_end_y);
        ctx.arc(condition_start_x - CONDOTION_CIRCLE, condition_end_y, CONDOTION_CIRCLE, 0, Math.PI * 2, true);
        ctx.stroke();
        this.drawText(ctx, text, condition_start_x - 10, condition_end_y + 5);
        this.conditionArray.push({
            x: Math.ceil(condition_start_x - CONDOTION_CIRCLE),
            y: Math.ceil(condition_end_y),
            conditionExpression: item.conditionExpression
        });
    }
    drwaProcess(arrData, ctx, dirctionFlag, conditionIndex = 0) {
        arrData.forEach((item) => {
            // 高亮当前节点 和 高亮走过的节点
            this.customerStrokeStyle(item, ctx, this.arrow_color);
            let process_start = FIRST_PROCESS_START_X + (item.index - 1) * (PROCESS_WIDTH + MEDIUM_LINE_LENGTH);
            if (item.nodeTyepName === 'EndEvent') {
                const end_y = dirctionFlag ? END_Y + PROCESS_WIDTH : END_Y - PROCESS_WIDTH;
                const last_end_y = dirctionFlag ? END_Y + PROCESS_WIDTH / 2 + 5 : END_Y - PROCESS_WIDTH / 2 - 5;
                const condition_end_y = dirctionFlag ? end_y + 15 : end_y - 15;
                const start = process_start + MEDIUM_LINE_LENGTH + PROCESS_WIDTH / 2;
                //   画结束的线
                ctx.beginPath();
                ctx.moveTo(start, last_end_y);
                ctx.lineTo(start, end_y);
                ctx.lineTo(END_X, end_y);
                // 画最后的箭头
                this.drawLineWithArrow(ctx, END_X, end_y, END_X, last_end_y, this.arrow_color);
                ctx.stroke();
                // 渲染条件
                if (item.conditionExpression) {
                    conditionIndex += 1;
                    const condition_start_x = start + (END_X - start) / 2;
                    this.drawCondition(ctx, conditionIndex, condition_start_x, condition_end_y, item);
                }
            } else {
                //   画箭头
                ctx.beginPath();
                this.drawLineWithArrow(ctx, process_start, END_Y, process_start + MEDIUM_LINE_LENGTH - 5, END_Y, this.arrow_color);
                ctx.stroke();
                // 画流程 => 矩形代替
                ctx.beginPath();
                ctx.save();
                this.imageToCanvas(
                    ctx,
                    this.nodeImg,
                    process_start + MEDIUM_LINE_LENGTH,
                    FIRST_PROCESS_START_Y,
                    PROCESS_WIDTH,
                    PROCESS_WIDTH,
                    true,
                    item.name
                );
                ctx.restore();
                ctx.stroke();
                // 画文本
                // 如果有条件 则画条件
                if (item.conditionExpression) {
                    conditionIndex += 1;
                    // 因为这里是上一个的条件 需要减去距离
                    const condition_start_x = process_start + MEDIUM_LINE_LENGTH / 2;
                    this.drawCondition(ctx, conditionIndex, condition_start_x, END_Y - 15, item);
                }
                if (item.childrenFlowNodeDto && item.childrenFlowNodeDto.length > 0) {
                    this.drwaProcess(item.childrenFlowNodeDto, ctx, !dirctionFlag, conditionIndex);
                }
            }
        });
    }
    //获取鼠标在canvas画布上的位置(**不是浏览器窗口的鼠标位置)
    getMousePos(canvas, evt) {
        var rect = canvas.getBoundingClientRect();
        return {
            x: evt.clientX - rect.left * (canvas.width / rect.width),
            y: evt.clientY - rect.top * (canvas.height / rect.height)
        };
    }
    draw() {
        const canvas = document.getElementById('myCanvas') as any;
        if (canvas && Object.prototype.hasOwnProperty.call(canvas, 'getContext')) {
            const ctx = canvas.getContext('2d');
            const that = this;
            const tempDom = document.querySelector('#temp') as any;
            canvas.addEventListener(
                'mousemove',
                function (evt) {
                    const mousePos = that.getMousePos(canvas, evt);
                    const pagex = mousePos.x,
                        pagey = mousePos.y;
                    // 定义当前坐标移动到  <20 && >-10 的情况下 出现条件
                    const areaobj = that.conditionArray.find((item) => {
                        const offsetX = item.x - pagex;
                        const offsetY = item.y - pagey;
                        return offsetX < 20 && offsetX > -10 && offsetY < 20 && offsetY > -10;
                    });
                    if (areaobj) {
                        tempDom.style.display = 'block';
                        tempDom.style.left = Number(areaobj.x + 20) + 'px';
                        tempDom.style.top = Number(areaobj.y - 20) + 'px';
                        tempDom.innerHTML = areaobj.conditionExpression;
                    } else {
                        tempDom.style.display = 'none';
                    }
                },
                false
            );
            // 画开始的圆
            ctx.font = '12px serif';
            ctx.lineCap = 'round';
            this.imageToCanvas(ctx, this.startImg, START_X, END_Y - 40, START_IMAGE_WIDTH, START_IMAGE_HEIGHT);

            //  这里需要根据数据去显示 对应的形状和路径
            this.drwaProcess(this.jsonData, ctx, true);
            //   结束的圆圈
            this.imageToCanvas(ctx, this.endImg, END_X - 40, END_Y - 40, START_IMAGE_WIDTH, START_IMAGE_HEIGHT);
        }
    }
    judgeIsArea() {}
}
</script>
<style lang="scss" scoped>
.conditionExpression-warrper {
    display: flex;
    font-size: 14px;
}
.list-warrper {
    position: relative;
    background: #fff;
    /deep/.warrper {
        top: 74px;
    }
}
.temp {
    position: absolute;
    height: auto;
    width: auto;
    padding: 6px;
    border: 1px solid #333;
    border-radius: 4px;
    color: #333;
    background: #fff;
}
</style>
